package com.wugh.fast.kernel.core.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;

/**
 * 说明:
 *
 * @author wugh
 * @date 2019-12-09 09:50
 */
public class SpelUtils {
    private SpelUtils() {
    }

    private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();

    /**
     * 获取spel表达式解析器
     *
     * @return
     */
    public static SpelExpressionParser getExpressionParser() {
        return EXPRESSION_PARSER;
    }

    /**
     * 通过切面创建表达式上下文
     * <pre>
     *      1. 支持常用的rootObject(method,args,target,targetClass) #root.method 或method
     *      2. 支持方法名称(JDK1.8之后) #p0 #a0 #argName
     *      3. 支持ioc容器, @beanName
     * </pre>
     *
     * @param joinPoint 切面对象
     * @return
     */
    public static EvaluationContext createEvaluationContext(JoinPoint joinPoint) {
        return createEvaluationContext(joinPoint, true);
    }

    /**
     * 通过切面创建表达式上下文
     * <pre>
     *     1. 支持常用的rootObject(method,args,target,targetClass) #root.method 或method
     *     2. 支持方法名称(JDK1.8之后) #p0 #a0 #argName
     *     3. 支持ioc容器, @beanName
     *     4. 支持返回值, #result
     * </pre>
     *
     * @param joinPoint     切面对象
     * @param useSpringBean 如果为true,则开启第三点
     * @return
     */
    public static EvaluationContext createEvaluationContext(JoinPoint joinPoint, boolean useSpringBean) {
        FastSpelContextBuilder builder = FastSpelContextBuilder.builder();
        handleBuilder(joinPoint, useSpringBean, builder);
        return builder.build();
    }

    /**
     * 通过切面创建表达式上下文
     * <pre>
     *     1. 支持常用的rootObject(method,args,target,targetClass) #root.method 或method
     *     2. 支持方法名称(JDK1.8之后) #p0 #a0 #argName
     *     3. 支持ioc容器, @beanName
     *     4. 支持返回值, #result
     * </pre>
     *
     * @param joinPoint 切面对象
     * @param result    返回值,通过#result可用
     * @return
     */
    public static EvaluationContext createEvaluationContext(JoinPoint joinPoint, Object result) {
        return createEvaluationContext(joinPoint, result, true);
    }

    /**
     * 通过切面创建表达式上下文
     * <pre>
     *     1. 支持常用的rootObject(method,args,target,targetClass) #root.method 或method
     *     2. 支持方法名称(JDK1.8之后) #p0 #a0 #argName
     *     3. 支持ioc容器, @beanName
     *     4. 支持返回值, #result
     * </pre>
     *
     * @param joinPoint     切面对象
     * @param result        返回值,通过#result可用
     * @param useSpringBean 如果为true,则开启第三点
     * @return
     */
    public static EvaluationContext createEvaluationContext(JoinPoint joinPoint, Object result, boolean useSpringBean) {
        FastSpelContextBuilder builder = FastSpelContextBuilder.builder();
        handleBuilder(joinPoint, useSpringBean, builder);
        builder.result(result);
        return builder.build();
    }

    private static void handleBuilder(JoinPoint joinPoint, boolean useSpringBean, FastSpelContextBuilder builder) {
        if (useSpringBean) {
            builder.useDefaultBeanResolver();
        }
        builder.arguments(joinPoint.getArgs());
        builder.target(joinPoint.getTarget());
        builder.targetClass(AopProxyUtils.ultimateTargetClass(joinPoint.getTarget()));
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            builder.method(((MethodSignature) signature).getMethod());
        }
    }
}
